﻿using MugenInjection.Core;
using MugenInjection.Interface;

namespace MugenInjection.Infrastructure
{
    /// <summary>
    ///     Represents a dependency that can be released by the dependent component.
    /// </summary>
    /// <typeparam name="T">The service provided by the dependency.</typeparam>
    public sealed class UoW<T> : DisposableObject
    {
        #region Fields

        private readonly IBindingContext _bindingContext;
        private readonly IInjector _injector;
        private readonly object _locker;
        private T _value;

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="UoW{T}" /> class.
        /// </summary>
        public UoW(IInjector injector, IBindingContext bindingContext)
        {
            Validate.ArgumentNotNull(injector, "injector");
            Validate.ArgumentNotNull(bindingContext, "bindingContext");
            _injector = injector.CreateChild(injector.Settings.Clone(),
                                             new ComponentContainer(), true,
                                             InjectorUtilsInternal.EmptyComponents);
            _bindingContext = bindingContext;
            _locker = new object();
        }

        #endregion

        #region Properties

        /// <summary>
        ///     Gets a value that indicates whether a value has been created for this <see cref="Managed{T}" /> instance.
        /// </summary>
        public bool IsValueCreated { get; set; }

        /// <summary>
        ///     Gets the lazily initialized value of the current <see cref="Managed{T}" /> instance.
        /// </summary>
        public T Value
        {
            get
            {
                if (IsValueCreated)
                    return _value;
                lock (_locker)
                {
                    if (IsValueCreated)
                        return _value;
                    _value = (T) _injector.Resolve(_bindingContext);
                    IsValueCreated = true;
                }
                return _value;
            }
        }

        #endregion

        #region Overrides of DisposableObject

        /// <summary>
        ///     Releases resources held by the object.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
                _injector.Dispose();
            base.Dispose(disposing);
        }

        #endregion
    }
}